#include <strmif.h>
#include "ac3parser.hpp"
#include <cassert>
#include <new>
//#ifdef _DEBUG
//#include "odbgstream.hpp"
//using std::endl;
//using std::hex;
//#endif

//The "Technical Details" section describes layour of AC-3 frame.
//http://en.wikipedia.org/wiki/Dolby_Digital

//Shows structure of AC3 frame:
//http://rmworkshop.com/dvd_info/related_info/ac3hdr.html

//http://liba52.sourceforge.net/
//Includes a52dec, a test program for liba52, and it has an
//mpeg-2 demultiplexer.  This might be useful if the Micrsoft
//mpeg-2 splitter and demultiplexer don't do what we want.

//From A/52B, Annex A of a_52a.pdf (14 June 2005)
//The AC-3 audio access unit (AU) or presentation unit (PU) is an 
//AC-3 sync frame. 
//The AC-3 sync frame contains 1536 audio samples. The duration of 
//an AC-3 access (or presentation) unit is 32 ms for audio sampled 
//at 48 kHz, approximately 34.83 ms for audio sampled at 44.1 kHz, 
//and 48 ms for audio sampled at 32 kHz.
    
namespace MkvMux
{

Ac3Parser::Chunk::Chunk() :
    m_buf(0),
    m_buflen(0),
    m_off_begin(0),
    m_off_end(0)
{
}


Ac3Parser::Chunk::Chunk(const BYTE* buf, ULONG buflen) :
    m_buf(Copy(buf, buflen)),
    m_buflen(buflen),
    m_off_begin(0),
    m_off_end(buf ? buflen : 0)
{
}


Ac3Parser::Chunk::Chunk(const Chunk& rhs) :
    m_buf(rhs.m_buf),
    m_buflen(rhs.m_buflen),
    m_off_begin(rhs.m_off_begin),
    m_off_end(rhs.m_off_end)
{
}


ULONG Ac3Parser::Chunk::len_front() const
{
    const ULONG len = m_off_end - m_off_begin;
    return len;
}


ULONG Ac3Parser::Chunk::len_back() const
{
    const ULONG len = m_buflen - m_off_end;
    return len;
}


BYTE* Ac3Parser::Chunk::Copy(const BYTE* src, ULONG len)
{
    if (src == 0)   //this is a key, not a real value
        return 0;
        
    BYTE* const tgt = new (std::nothrow) BYTE[len];
    assert(tgt);  //TODO
    
    memcpy(tgt, src, len);
    
    return tgt;
}


Ac3Parser::ConstIterator
Ac3Parser::ConstIterator::begin(const Ac3Parser* p)
{
    assert(p);
    
    if (p->m_len == 0)
        return end(p);
    
    ConstIterator i(p);
    
    i.m_off = 0;
    
    const chunk_list_t& a = p->m_active;
    assert(!a.empty());
    
    i.m_chunk_iter = a.begin();
    
    const Chunk& c = *i.m_chunk_iter;
    i.m_chunk_off = c.m_off_begin;        
    
    return i;
}
    
    
Ac3Parser::ConstIterator
Ac3Parser::ConstIterator::end(const Ac3Parser* p)
{
    assert(p);
    
    ConstIterator i(p);
    
    i.m_off = p->m_len;    
    i.m_chunk_iter = p->m_active.end();    
    i.m_chunk_off = 0;
    
    return i;
}
    
    
Ac3Parser::ConstIterator::ConstIterator(const Ac3Parser* p) : m_parser(p)
{
    //NOTE: remaining initialization is done in begin() or end().
}


Ac3Parser::ConstIterator::ConstIterator(const ConstIterator& rhs) :
    m_parser(rhs.m_parser),
    m_chunk_iter(rhs.m_chunk_iter),
    m_chunk_off(rhs.m_chunk_off),
    m_off(rhs.m_off)
{
}


Ac3Parser::ConstIterator&
Ac3Parser::ConstIterator::operator=(const ConstIterator& rhs)
{
    if (&rhs == this)
        return *this;
        
    assert(this->m_parser == rhs.m_parser);
    
    m_chunk_iter = rhs.m_chunk_iter;
    m_chunk_off = rhs.m_chunk_off;
    m_off = rhs.m_off;
    
    return *this;
}



BYTE Ac3Parser::ConstIterator::operator*() const
{
    assert(m_parser);
    assert(m_off < m_parser->m_len);
    assert(m_chunk_iter != m_parser->m_active.end());
    
    const Chunk& c = *m_chunk_iter;
    assert(c.m_buf);
    assert(c.m_buflen);
    assert(c.m_off_end <= c.m_buflen);
    assert(c.m_off_begin < c.m_off_end);
    assert(m_chunk_off >= c.m_off_begin);
    assert(m_chunk_off < c.m_off_end);
    
    return c.m_buf[m_chunk_off];
}


Ac3Parser::ConstIterator&
Ac3Parser::ConstIterator::operator++()  //pre-fix
{
    assert(m_parser);
    assert(m_off < m_parser->m_len);
    assert(m_chunk_iter != m_parser->m_active.end());

    const Chunk& c = *m_chunk_iter;
    assert(c.m_buf);
    assert(c.m_buflen);
    assert(c.m_off_end <= c.m_buflen);
    assert(c.m_off_begin < c.m_off_end);
    assert(m_chunk_off >= c.m_off_begin);
    assert(m_chunk_off < c.m_off_end);

    ++m_off;
    assert(m_off <= m_parser->m_len);
    
    ++m_chunk_off;
    
    if (m_chunk_off >= c.m_off_end)
    {
        ++m_chunk_iter;
        m_chunk_off = 0;
        
        assert((m_chunk_iter != m_parser->m_active.end()) || (m_off == m_parser->m_len));
    }
    
    return *this;
}


Ac3Parser::ConstIterator
Ac3Parser::ConstIterator::operator++(int)  //post-fix
{
    const ConstIterator result(*this);
    this->operator++();
    return result;
}

    
bool Ac3Parser::ConstIterator::operator==(const ConstIterator& rhs) const
{
    assert(this->m_parser);
    assert(rhs.m_parser);
    assert(this->m_parser == rhs.m_parser);

    if (this->m_chunk_iter != rhs.m_chunk_iter)
        return false;
        
    if (this->m_chunk_off != rhs.m_chunk_off)
        return false;
        
    assert(this->m_off == rhs.m_off);

    return true;
}

    
bool Ac3Parser::ConstIterator::operator!=(const ConstIterator& rhs) const
{
    return !this->operator==(rhs);
}


ULONG Ac3Parser::ConstIterator::off() const
{
    return m_off;
}


LONG Ac3Parser::ConstIterator::operator-(const ConstIterator& rhs) const
{
    const LONG result = LONG(this->m_off) - LONG(rhs.m_off);
    return result;
}



void Ac3Parser::ConstIterator::Advance(ULONG n)
{
    while (n > 0)
    {
        assert(m_chunk_iter != m_parser->m_active.end());
        
        const Chunk& c = *m_chunk_iter;
        assert(c.m_buf);
        assert(c.m_buflen);
        assert(c.m_off_end <= c.m_buflen);
        assert(c.m_off_begin < c.m_off_end);
        assert(m_chunk_off >= c.m_off_begin);
        assert(m_chunk_off < c.m_off_end);
        
        const ULONG m = c.m_off_end - m_chunk_off;
        
        if (m > n)
        {
            m_chunk_off += n;
            m_off += n;
            
            return;
        }
        
        ++m_chunk_iter;
        m_chunk_off = 0;
        m_off += m;
        
        n -= m;
    }
}


Ac3Parser::ConstIterator
Ac3Parser::ConstIterator::operator+(ULONG n) const
{
    ConstIterator result(*this);
    result.Advance(n);
    return result;
}



Ac3Parser::ConstIterator Ac3Parser::begin() const
{
    return ConstIterator::begin(this);
}


Ac3Parser::ConstIterator Ac3Parser::end() const
{
    return ConstIterator::end(this);
}


Ac3Parser::Frame::Frame(BYTE* p, ULONG n) :
    m_buf(p),
    m_buflen(n)
{
}


Ac3Parser::Frame::~Frame()
{
    delete[] m_buf;
}


void Ac3Parser::Frame::Destroy(Frame* p)
{
    delete p;    //TODO: create a pool, so we can reuse frames
}


const BYTE* Ac3Parser::Frame::buf() const
{
    return m_buf;
}


ULONG Ac3Parser::Frame::buflen() const
{
    return m_buflen;
}


ULONG Ac3Parser::Frame::timecode_ms() const
{
    return m_timecode_ms;
}


Ac3Parser::FrameIterator::FrameIterator(Ac3Parser* p) :
    m_iter(p->begin()),
    m_iter_end(p->end()),
    m_off(7)
{
}


unsigned Ac3Parser::FrameIterator::ReadBits(int nBits)
{
    assert(nBits >= 0);
    assert(nBits <= 31);
    assert(m_iter != m_iter_end);
    assert(m_off >= 0);
    assert(m_off <= 7);
    
    unsigned result = 0;
    
    while (nBits > 0)
    {
        assert(m_iter != m_iter_end);
        assert(m_off >= 0);
        assert(m_off <= 7);
        
        const BYTE B = *m_iter;
        const BYTE b = BYTE(B >> m_off) & 0x01;
        
        result <<= 1;
        result |= b;
        
        --m_off;
        
        if (m_off < 0)
        {
            ++m_iter;
            m_off = 7;
        }

        --nBits;        
    }
    
    return result;
}


unsigned Ac3Parser::FrameIterator::operator()(int nBits)
{
    return ReadBits(nBits);
}


Ac3Parser::Ac3Parser() :
    m_len(0),
    m_samples(0),
    m_state(&Ac3Parser::StateFindFrameStart),
    m_bEOS(false)
{
}


Ac3Parser::~Ac3Parser()
{
    while (!m_active.empty())
    {
        Chunk& c = m_active.front();

        delete[] c.m_buf;
        
        m_active.pop_front();
    }
    
    typedef chunk_set_t::iterator iter_t;
    
    iter_t i = m_free.begin();
    const iter_t j = m_free.end();
    
    while (i != j)
    {
        Chunk& c = *i;
        
        delete[] c.m_buf;
        
        m_free.erase(i++);
    }
}
        
        

void Ac3Parser::Enqueue(const BYTE* src, ULONG srclen)
{
    if (srclen == 0)
        return;
        
    assert(src);
    
    if (!m_active.empty())
    {
        Chunk& c = m_active.back();
        assert(c.m_off_end >= c.m_off_begin);
        assert(c.m_off_end <= c.m_buflen);
        
        BYTE* const tgt = c.m_buf + c.m_off_end;
        
        const ULONG len_back = c.len_back();

        if (len_back >= srclen)
        {
            memcpy(tgt, src, srclen);            
            c.m_off_end += srclen;
            m_len += srclen;
            
            Parse();
            return;
        }
        
        memcpy(tgt, src, len_back);
        c.m_off_end += len_back;
        m_len += len_back;
        
        src += len_back;
        srclen -= len_back;
    }
    
    typedef chunk_set_t::iterator iter_t;
    
    const iter_t iter = m_free.lower_bound(Chunk(0, srclen));
    
    if (iter == m_free.end())
    {
        m_active.push_back(Chunk(src, srclen));
        m_len += srclen;
        
        Parse();
        return;
    }
    
    m_active.push_back(Chunk(*iter));
    m_free.erase(iter);
    
    Chunk& c = m_active.back();
    assert(c.m_buflen >= srclen);
    
    c.m_off_begin = 0;
    c.m_off_end = srclen;
            
    memcpy(c.m_buf, src, srclen);
    m_len += srclen;
    
    Parse();
}


void Ac3Parser::EndOfStream()
{
   m_bEOS = true;
   Parse();
}


Ac3Parser::Frame* Ac3Parser::Dequeue()
{
    if (m_frames.empty())
        return 0;
        
    Frame* const f = m_frames.front();
    m_frames.pop_front();
    
    return f;
}


void Ac3Parser::Parse()
{
    for (;;)
    {
        const bool done = (this->*m_state)();
        
        if (done)
            return;
    }
}


bool Ac3Parser::StateFindFrameStart()
{
    //We hope we never have to throw away data here, 
    //because that will probably throw off the a/v sync.
    
    while (m_len >= 2)
    {
        if (Curr() != 0x0B)
        {
            Consume();
            continue;
        }
        
        if (Next() != 0x77)
        {
            Consume();
            continue;
        }
            
        m_state = &Ac3Parser::StateFindFrameSize;
        return false;  //not done
    }            
    
    return true;  //done (no change in state)
}


bool Ac3Parser::StateFindFrameSize()
{
    assert(m_len >= 2);
    assert(Curr() == 0x0B);
    assert(Next() == 0x77);
    
    if (m_len < 5)  //sync word + crc + (fscod | frmsiz)
        return true;  //done (need more data)
    
    FrameIterator i(this);
    
    const unsigned sync = i(16);
    assert(sync == 0x0B77);
    sync;
    
    const unsigned crc1 = i(16);
    crc1;  //TODO: use CRC to check frame
        
    //TODO:
    //It these checks fail, then it probably means that
    //the sync word we found (and that caused us to
    //transition this parse state) was spurious.  In that
    //case we'll have to transition back to StateFindFrameStart
    //to find the next sync word, and then try again.  We 
    //pretty much need to use the CRC here, because it will
    //tell us definitively whether we have an actual sync
    //word, instead of a spurious one.
    //END TODO.    
    
    const unsigned fscod = i(2);
    assert(fscod != 3);  //reserved  //TODO: does this imply pass on, but mute frame?
    assert(fscod == 0);  //TODO: handle 48K only for now
    
    const unsigned frmsizcod = i(6);
    assert(frmsizcod <= 37);
    
    const USHORT* const frmsizcod_table = s_frmsizcod_table[fscod];
    const USHORT frmsiz = frmsizcod_table[frmsizcod];  //number of 16-bit words
    m_frame_len = ULONG(frmsiz) * 2;                         //number of bytes

    m_state = &Ac3Parser::StateFindFrameStop;
    return false;  //not done
}


bool Ac3Parser::StateFindFrameStop()
{
    assert(m_len >= 5);
    assert(Curr() == 0x0B);
    assert(Next() == 0x77);
    assert(m_frame_len >= 5);
    
    if (m_len < (m_frame_len + 2))
    {
        if (m_bEOS && (m_len >= m_frame_len))
            ConstructFrame(m_len);    

        return true;  //done (need more data)
    }
    
    ConstIterator iter = begin() + m_frame_len;
    
    const ConstIterator iter_end = end();
    assert((iter_end - iter) >= 2);
    
    //Hopefully this loop should execuate exactly once.
    //If the frmsizcod isn't lying to us, we should already
    //be positioned on the sync word that starts the next frame.
    
    //TODO: the sync word should be word-aligned in the stream.
    //(That's why frmsiz is "number of 16-bit words".)  This will 
    //help us avoid spurious sync words.
    
    while (iter != iter_end)
    {
        if ((*iter != 0x0B) || ((iter.off() % 2) != 0))
        {
            ++iter;
            continue;
        }
        
        ConstIterator next_iter = ++ConstIterator(iter);
        
        if (next_iter == iter_end)
            return true;  //done (need more data)
        
        if (*next_iter != 0x77)
        {
            iter = ++next_iter;
            continue;
        }
            
        //What we would like to say:
        //assert(len == m_frame_len);

        ConstructFrame(iter.off());
        assert(m_len >= 2);
        assert(Curr() == 0x0B);
        assert(Next() == 0x77);
        
        m_state = &Ac3Parser::StateFindFrameSize;
        return false;  //not done yet
    }            
    
    return true;  //done (need more data)
}


BYTE Ac3Parser::Curr() const
{
    assert(m_len >= 1);
    assert(!m_active.empty());
    
    const Chunk& c = m_active.front();
    assert(c.m_buf);
    assert(c.m_buflen);
    assert(c.m_off_end <= c.m_buflen);
    assert(c.m_off_begin < c.m_off_end);
    
    return c.m_buf[c.m_off_begin];
}


BYTE Ac3Parser::Next() const
{
    assert(m_len >= 2);

    assert(!m_active.empty());
    
    typedef chunk_list_t::const_iterator iter_t;
    
    iter_t i = m_active.begin();

    {
        const Chunk& c = *i++;
        assert(c.m_buf);
        assert(c.m_buflen);
        assert(c.m_off_end <= c.m_buflen);
        assert(c.m_off_begin < c.m_off_end);
        
        const ULONG off = c.m_off_begin + 1;

        if (off < c.m_off_end)
            return c.m_buf[off];
    }
    
    assert(i != m_active.end());
    
    const Chunk& c = *i;
    assert(c.m_buf);
    assert(c.m_buflen);
    assert(c.m_off_end <= c.m_buflen);
    assert(c.m_off_begin < c.m_off_end);
    assert(c.m_off_begin == 0);
    
    return c.m_buf[0];
}


void Ac3Parser::Consume(ULONG len)
{
    assert(len <= m_len);

    while (len > 0)
    {
        assert(!m_active.empty());
        
        Chunk& c = m_active.front();
        assert(c.m_buf);
        assert(c.m_buflen);
        assert(c.m_off_end <= c.m_buflen);
        assert(c.m_off_begin < c.m_off_end);
        
        const ULONG n = c.m_off_end - c.m_off_begin;
        
        if (n > len)
        {
            c.m_off_begin += len;
            m_len -= len;
            return;
        }
        
        m_free.insert(c);
        m_active.pop_front();
        
        m_len -= n;
        len -= n;
    }
}
    

void Ac3Parser::ConstructFrame(ULONG len)
{
//#ifdef _DEBUG
//    odbgstream os;
//    os << "Ac3Parser::ConstructFrame: len=" << len << endl;
//#endif

    assert(len >= 5);
    assert(m_len >= len);
    assert(Curr() == 0x0B);
    assert(Next() == 0x77);
    
    //Ideally, the BSI would have a timecod, but we can't 
    //rely on that.  However, assuming this is a mux from
    //the start of the movie, then we should be able to 
    //just count samples and determine the time that way.
    SyncFrame();
    
    const __int64 timecode_ms = m_samples / 48;  //TODO: assumes 48K
    m_samples += 1536;
        
    BYTE* buf = new (std::nothrow) BYTE[len];
    assert(buf);  //TODO

    Frame* const f = new (std::nothrow) Frame(buf, len);
    assert(f);  //TODO
    
    f->m_timecode_ms = static_cast<ULONG>(timecode_ms);
        
    while (len > 0)
    {
        assert(!m_active.empty());
        
        Chunk& c = m_active.front();
        assert(c.m_buf);
        assert(c.m_buflen);
        assert(c.m_off_end <= c.m_buflen);
        assert(c.m_off_begin < c.m_off_end);
        
        const ULONG len_front = c.len_front();
        assert(len_front > 0);
        assert(len_front <= m_len);
        
        const BYTE* const src = c.m_buf + c.m_off_begin;
        
        if (len_front > len)
        {
            memcpy(buf, src, len);            
            c.m_off_begin += len;
            break;
        }
        
        memcpy(buf, src, len_front);
        
        m_free.insert(c);
        m_active.pop_front();

        buf += len_front;        
        len -= len_front;
    }
    
    assert(m_len >= f->m_buflen);
    m_len -= f->m_buflen;    
    //assert(m_len >= 2);
    
    m_frames.push_back(f);
}


void Ac3Parser::SyncFrame()
{
    FrameIterator i(this);
    
    const unsigned sync = i(16);
    assert(sync == 0x0B77);
    sync;
    
    const unsigned crc1 = i(16);
    crc1;  //TODO
    
    const unsigned fscod = i(2);
    assert(fscod == 0);  //TODO: for now, 48K only
    fscod;
    
    const unsigned frmsizcod = i(6);
    assert(frmsizcod < 38);    
    frmsizcod;
    
    BSI(i);
}


void Ac3Parser::BSI(FrameIterator& i)
{
    const unsigned bsid = i(5);
    assert(bsid == 8);  //TODO: handle other values
    bsid;
    
    const unsigned bsmod = i(3);
    bsmod;
    
    const unsigned acmod = i(3);
    acmod;
    
    //odbgstream os;
    //os << "BSI: bsid=" << bsid 
    //   << " bsmod=" << bsmod
    //   << " acmod=" << acmod
    //   << std::flush;    

    if ((acmod & 0x1) && (acmod != 0x1))  //3 front channels
    {
        const unsigned cmixlev = i(2);
        cmixlev;
    }
    
    if (acmod & 0x4)  //surround channel
    {
        const unsigned surmixlev = i(2);
        surmixlev;
    }
    
    if (acmod == 0x2) //in 2/0 mode
    {
        const unsigned dsurmod = i(2);
        dsurmod;
    }
    
    const unsigned lfeon = i(1);
    lfeon;
    
    const unsigned dialnorm = i(5);
    dialnorm;
    
    const unsigned compre = i(1);
    
    if (compre)
    {
        const unsigned compr = i(8);
        compr;
    }
    
    const unsigned langcode = i(1);
    
    if (langcode)
    {
        const unsigned langcod = i(8);
        langcod;
    }
    
    const unsigned audprodie = i(1);
    
    if (audprodie)
    {
        const unsigned mixlevel = i(5);
        mixlevel; 
        
        const unsigned roomtyp = i(2);
        roomtyp;
    }
    
    if (acmod == 0)
    {
        const unsigned dialnorm2 = i(5);
        dialnorm2;
        
        const unsigned compr2e = i(1);
        
        if (compr2e)
        {
            const unsigned compr2 = i(8);
            compr2;
        }
        
        const unsigned langcod2e = i(1);
        
        if (langcod2e)
        {
            const unsigned langcod2 = i(8);
            langcod2;
        }
        
        const unsigned audproi2e = i(1);
        
        if (audproi2e)
        {
            const unsigned mixlevel2 = i(5);
            mixlevel2;
            
            const unsigned roomtyp2 = i(2);
            roomtyp2;
        }
    }

    const unsigned copyrightb = i(1);
    copyrightb;
    
    const unsigned origbs = i(1);
    origbs;
    
    const unsigned timecod1e = i(1);
    
    if (timecod1e)
    {   
        const unsigned timecod1 = i(14);
        timecod1;
        
        //os << " timecod1=0x" << hex << timecod1;
    }
    //else
    //    os << " timecod1=[NONE]";
    
    const unsigned timecod2e = i(1);
    
    if (timecod2e)
    {
        const unsigned timecod2 = i(14);
        timecod2;
        
        //os << " timecod2=0x" << hex << timecod2;
    }
    //else
    //    os << " timecod2=[NONE]";
        
    //os << endl;
    
    const unsigned addbsie = i(1);
    
    if (addbsie)
    {
        const unsigned addbsil = i(6);      
        const unsigned n = addbsil + 1;
        
        for (unsigned idx = 0; idx < n; ++idx)
        {
            const unsigned b = i(8);
            b;
        }
    }
}




//              32 441 48
//000000 32Kbps 96 69 64 
//000001 32Kbps 96 70 64 
//000010 40Kbps 120 87 80 
//000011 40Kbps 120 88 80 
//000100 48Kbps 144 104 96 
//000101 48Kbps 144 105 96 
//000110 56Kbps 168 121 112 
//000111 56Kbps 168 122 112 
//001000 64Kbps 192 139 128 
//001001 64Kbps 192 140 128 
//001010 80Kbps 240 174 160 
//001011 80Kbps 240 175 160 
//001100 96Kbps 288 208 192 
//001101 96Kbps 288 209 192 
//001110 112Kbps 336 243 224 
//001111 112Kbps 336 244 224 
//010000 128Kbps 384 278 256 
//010001 128Kbps 384 279 256 
//010010 160Kbps 480 348 320 
//010011 160Kbps 480 349 320 
//010100 192Kbps 576 417 384 
//010101 192Kbps 576 418 384 
//010110 224Kbps 672 487 448 
//010111 224Kbps 672 488 448 
//011000 256Kbps 768 557 512 
//011001 256Kbps 768 558 512 
//011010 320Kbps 960 696 640 
//011011 320Kbps 960 697 640 
//011100 384Kbps 1152 835 768 
//011101 384Kbps 1152 836 768 
//011110 448Kbps 1344 975 896 
//011111 448Kbps 1344 976 896 
//100000 512Kbps 1536 1114 1024 
//100001 512Kbps 1536 1115 1024 
//100010 576Kbps 1728 1253 1152 
//100011 576Kbps 1728 1254 1152 
//100100 640Kbps 1920 1393 1280 
//100101 640Kbps 1920 1394 1280 

const USHORT Ac3Parser::s_frmsizcod_table[][38] =  //TODO: for now, just handle 48K
{

{
64, //000000
64, //000001
80, //000010
80, //000011
96, //000100
96, //000101
112, //000110
112, //000111
128, //001000
128, //001001
160, //001010
160, //001011
192, //001100
192, //001101
224, //001110
224, //001111
256, //010000
256, //010001
320, //010010
320, //010011
384, //010100
384, //010101
448, //010110
448, //010111
512, //011000
512, //011001
640, //011010
640, //011011
768, //011100
768, //011101
896, //011110
896, //011111
1024, //100000
1024, //100001
1152, //100010
1152, //100011
1280, //100100
1280 //100101
}

};


}  //MkvMux
